﻿using SL651Center2.x.Enums;
using System.Globalization;
using System.Text;
using TouchSocket.Core;

namespace SL651Center2.x.Messages
{
    /// <summary>
    /// 报头
    /// </summary>
    public class MessageFrame : TelemetryInfo
    {
        public static readonly byte[] ASCII = { 0x01 };
        public static readonly byte[] HEX_BCD = { 0x7E, 0x7E };
        /// <summary>
        /// 帧起始符
        /// </summary>
        public byte[] FrameCoding { get; private set; } = Array.Empty<byte>();

        /// <summary>
        /// 中心站地址的十六进制字符串
        /// </summary>
        public string CentralAddressStr { get; set; } = string.Empty;

        /// <summary>
        /// 遥测站地址的十六进制字符串
        /// </summary>
        public string TelemetryAddressStr { get; set; } = string.Empty;

        /// <summary>
        /// 密码的十六进制字符串
        /// </summary>
        public string PassWordStr { get; set; } = string.Empty;
        /// <summary>
        /// 功能码
        /// </summary>
        public FunctionCode FunctionCode { get; set; }
        //public byte FunctionCode { get; set; }
        /// <summary>
        /// 报文上下行及表示长度
        /// </summary>
        public byte[] MessageType { get; set; } = Array.Empty<byte>();
        /// <summary>
        /// 正文长度
        /// </summary>
        public int MessageLength { get; set; }
        /// <summary>
        /// 报文起始符
        /// </summary>
        public StartMarks StartMark { get; set; }

        /// <summary>
        /// 包总数及序列号
        /// </summary>
        public byte[] Package { get; set; } = Array.Empty<byte>();
        /// <summary>
        /// 包总数
        /// </summary>
        public int PackageCount { get; set; }
        /// <summary>
        /// 包序列号
        /// </summary>
        public int PackageIndex { get; set; }
        /// <summary>
        /// 报文结束符
        /// </summary>
        public EndMarks EndMark { get; set; }

        /// <summary>
        /// 读取帧头和帧尾
        /// </summary>
        /// <param name="byteBlock">字节块流</param>
        public void ReadHead(in ByteBlock byteBlock)
        {
            if (FrameCode==FrameCode.ASCII)
            {
                ReadHeadASCII(byteBlock);
                return;
            }
            //读取中心站地址
            CentralAddress = byteBlock.ReadToSpan(1).ToArray();
            //中心站地址十六进制字符串
            CentralAddressStr = Helper.ToHEXString(CentralAddress);
            //读取遥测站地址
            TelemetryAddress=byteBlock.ReadToSpan(5).ToArray();
            //遥测站地址的字符串形式
            TelemetryAddressStr = TelemetryAddress.ByBytesToHexString();
            //读取密码
            PassWord=byteBlock.ReadToSpan(2).ToArray();
            //密码的十六进制字符串
            PassWordStr = Helper.ToHEXString(PassWord);
            //读取功能码
            FunctionCode = (FunctionCode)byteBlock.ReadByte();
            //报文上下行标识及长度
            MessageType = byteBlock.ReadToSpan(2).ToArray();
            //报文长度
            //MessageLength = BitConverter.ToInt16(MessageType);
            MessageLength = Convert.ToUInt16(Helper.ToHEXString(MessageType), 16);
            //报文起始符
            StartMark = (StartMarks)byteBlock.ReadByte();
            //如果是多包传输读取包总数和序列号
            if (StartMark == StartMarks.SYN)
            {
                //包总数和序列号
                Package = byteBlock.ReadToSpan(3).ToArray();
                var h = Helper.ToHEXString(Package);
                //包总数
                PackageCount = Convert.ToUInt16(h[..3], 16);
                //包序列号
                PackageIndex = Convert.ToUInt16(h[3..], 16);
            }
            //报文结束符
            EndMark = (EndMarks)byteBlock.Span[byteBlock.Length - 3];

        }

        /// <summary>
        /// 读取ASCII格式的帧头和帧尾
        /// </summary>
        /// <param name="byteBlock">字节块流</param>
        void ReadHeadASCII(in ByteBlock byteBlock)
        {
            //读取中心站地址
            CentralAddress = byteBlock.ReadToSpan(2).ToArray();
            //中心站地址的十六进制字符串
            CentralAddressStr = CentralAddress.ToASCIIString();
            //读取遥测站地址
            TelemetryAddress = byteBlock.ReadToSpan(10).ToArray();
            //遥测站地址的字符串形式
            TelemetryAddressStr = TelemetryAddress.ToASCIIString();
            //读取密码
            PassWord = byteBlock.ReadToSpan(4).ToArray();
            //密码的十六进制字符串
            PassWordStr = PassWord.ToASCIIString();
            //读取功能码
            var fccode = new byte[2];
            byteBlock.Read(fccode);
            var fnhs = fccode.ToASCIIString();
            var fnh = byte.Parse(fnhs, NumberStyles.HexNumber);
            FunctionCode = (FunctionCode)fnh;
            //报文上下行标识及长度            
            MessageType = byteBlock.ReadToSpan(4).ToArray();
            //报文长度
            var uh = Encoding.ASCII.GetString(MessageType);
            MessageLength = Convert.ToUInt16(uh, 16);
            //报文起始符
            StartMark = (StartMarks)byteBlock.ReadByte();
            //如果是多包传输读取包总数和序列号
            if (StartMark == StartMarks.SYN)
            {
                //包总数和序列号
                Package = byteBlock.ReadToSpan(6).ToArray();
                var h = Package.ToASCIIString();
                //包总数
                PackageCount = Convert.ToUInt16(h[..3], 16);
                //包序列号
                PackageIndex = Convert.ToUInt16(h[3..], 16);
            }
            //报文结束符
            EndMark = (EndMarks)byteBlock[byteBlock.Length - 5];

        }

        /// <summary>
        /// 检查CRC校验码
        /// </summary>
        /// <param name="byteBlock">字节块流</param>
        /// <returns>true:CRC校验码正确。false:CRC校验码错误</returns>
        public bool CheckCRC(in ByteBlock byteBlock)
        {
            //计算校验码
            if (FrameCoding.Length == 1)
            {
                return CheckCRCASCII(byteBlock);
            }

            var crc = Helper.Crc16(byteBlock.ToArray(), 0, byteBlock.Length - 2);
            var crc1 = byteBlock.ToArray(byteBlock.Length - 2, 2);

            if (crc[0] == crc1[0] && crc[1] == crc1[1])
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 检查CRC校验码
        /// </summary>
        /// <param name="byteBlock">字节块流</param>
        /// <returns>true:CRC校验码正确。false:CRC校验码错误</returns>
        static bool CheckCRCASCII(in ByteBlock byteBlock)
        {
            var crc = Helper.Crc16(byteBlock.ToArray(), 0, byteBlock.Length - 4);
            string c = Encoding.ASCII.GetString(byteBlock.ToArray(), byteBlock.Length - 4, 4);
            var crc1 = Helper.HEXStrToByte(c);
            if (crc[0] == crc1[0] && crc[1] == crc1[1])
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 设置帧编码格式
        /// </summary>
        /// <param name="bytes"></param>
        public void SetFrameCode(ReadOnlySpan<byte> bytes)
        {
            FrameCode= bytes.Length==1? Enums.FrameCode.ASCII : Enums.FrameCode.HEX＿BCD;
            FrameCoding = bytes.ToArray();
        }
    }

}
